﻿using Microsoft.VisualStudio.TestTools.UnitTesting;
using MongoDB.Driver;
using Sustainalytics.DataLayer.PI;
using Sustainalytics.Entities.ProductInvolvement;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Sustainalytics.DataLayer.Tests.PI
{
    [TestClass]
    public class PIIndicatorRepositoryTests
    {
        private IProductInvolvementFrameworkRepository piIndicatorRepository;
        private string dbCnx = "mongodb://localhost:27017/ClientDW_Tests";
        private string databaseName = "ClientDW_Tests";
        private IMongoDatabase database = null;
        private List<ProductInvolvementFramework> piIndicators;

        [TestInitialize]
        public void Initialize()
        {
            var mongoClient = new MongoClient(dbCnx);
            database = mongoClient.GetDatabase(databaseName);

            database.CreateCollection("PIIndicator");
            var piIndicatorCollection = database.GetCollection<ProductInvolvementFramework>();

            piIndicators = new List<ProductInvolvementFramework>();
            PopulatePiIndicators();

            piIndicatorCollection.InsertMany(piIndicators);
            piIndicatorRepository = new ProductInvolvementFrameworkRepository(dbCnx);
        }

        #region Utils

        private void PopulatePiIndicators()
        {
            piIndicators.Add(new ProductInvolvementFramework()
            {
                Id = Guid.NewGuid(),
                Name = "Palm Oil",
                Symbol = "PM",
                Categories = new List<ProductInvolvementCategory>() {
                    new ProductInvolvementCategory(){
                             Symbol = "PM1",
                             CategoryOfInvolvement = "Production",
                             RelatedCategorySymbol = "",
                             Description = "The company produces palm oil",
                             OwnershipYesNo = false,
                             RevenueRangeYesNo = true,
                             RevenueRange = new Dictionary<int,PIRange>()
                             {
                                 { 0, new PIRange(){ RangeId = 1, NA = false, Start = 0, Stop = 4.89}},
                                 { 1, new PIRange(){ RangeId = 2, NA = false, Start = 5, Stop = 9.89}},
                                 { 2, new PIRange(){ RangeId = 3, NA = false, Start = 10, Stop = 24.89}},
                                 { 3, new PIRange(){ RangeId = 4, NA = false, Start = 25, Stop = 49.89}},
                                 { 4, new PIRange(){RangeId = 5, NA = false, Start = 50, Stop = 100}}
                             }
                    },
                    new ProductInvolvementCategory() {
                            Symbol = "PM2",
                            CategoryOfInvolvement = "Significant ownership (production)",
                            RelatedCategorySymbol = "PM1",
                            Description = "The company owns 10-50 percent of a company that produces palm oil",
                            OwnershipYesNo = true,
                            RevenueRangeYesNo = false,
                            RevenueRange = new Dictionary<int,PIRange>()
                            {
                                { 0, new PIRange(){ RangeId = 1, NA = true, Start = -1, Stop = -1}},
                                { 1, new PIRange(){ RangeId = 2, NA = true, Start = -1, Stop = -1}},
                                { 2, new PIRange(){ RangeId = 3, NA = true, Start = -1, Stop = -1}},
                                { 3, new PIRange(){ RangeId = 4, NA = true, Start = -1, Stop = -1}},
                                { 4, new PIRange(){RangeId = 5, NA = true, Start = -1, Stop = -1}}
                            }
                    },
                    new ProductInvolvementCategory() {
                            Symbol = "PM3",
                            CategoryOfInvolvement = "Refining and retail",
                            RelatedCategorySymbol = "",
                            Description = "The company refines or trades palm oil",
                            OwnershipYesNo = false,
                            RevenueRangeYesNo = true,
                            RevenueRange = new Dictionary<int,PIRange>()
                            {
                                 { 0, new PIRange(){ RangeId = 1, NA = false, Start = 0, Stop = 4.89}},
                                 { 1, new PIRange(){ RangeId = 2, NA = false, Start = 5, Stop = 9.89}},
                                 { 2, new PIRange(){ RangeId = 3, NA = false, Start = 10, Stop = 24.89}},
                                 { 3, new PIRange(){ RangeId = 4, NA = false, Start = 25, Stop = 49.89}},
                                 { 4, new PIRange(){RangeId = 5, NA = false, Start = 50, Stop = 100}}
                            }
                    },
                    new ProductInvolvementCategory() {
                            Symbol = "PM4",
                            CategoryOfInvolvement = "Significant ownership (refining and retail)",
                            RelatedCategorySymbol = "PM3",
                            Description = "The company owns 10-50 percent of a company that refines or trades palm oil",
                            OwnershipYesNo = true,
                            RevenueRangeYesNo = false,
                            RevenueRange = new Dictionary<int,PIRange>()
                            {
                                { 0, new PIRange(){ RangeId = 1, NA = true, Start = -1, Stop = -1}},
                                { 1, new PIRange(){ RangeId = 2, NA = true, Start = -1, Stop = -1}},
                                { 2, new PIRange(){ RangeId = 3, NA = true, Start = -1, Stop = -1}},
                                { 3, new PIRange(){ RangeId = 4, NA = true, Start = -1, Stop = -1}},
                                { 4, new PIRange(){RangeId = 5, NA = true, Start = -1, Stop = -1}}
                            }
                    }
                }
            });
            piIndicators.Add(new ProductInvolvementFramework()
            {
                Id = Guid.NewGuid(),
                Name = "Predatory Lending",
                Symbol = "PL",
                Categories = new List<ProductInvolvementCategory>() {
                    new ProductInvolvementCategory(){
                             Symbol = "PL1",
                             CategoryOfInvolvement = "Operations",
                             RelatedCategorySymbol = "",
                             Description = "The company is involved in predatory lending activities",
                             OwnershipYesNo = false,
                             RevenueRangeYesNo = true,
                             RevenueRange = new Dictionary<int,PIRange>()
                             {
                                 { 0, new PIRange(){ RangeId = 1, NA = false, Start = 0, Stop = 4.89}},
                                 { 1, new PIRange(){ RangeId = 2, NA = false, Start = 5, Stop = 9.89}},
                                 { 2, new PIRange(){ RangeId = 3, NA = false, Start = 10, Stop = 24.89}},
                                 { 3, new PIRange(){ RangeId = 4, NA = false, Start = 25, Stop = 49.89}},
                                 { 4, new PIRange(){RangeId = 5, NA = false, Start = 50, Stop = 100}}
                             }
                    },
                    new ProductInvolvementCategory() {
                            Symbol = "PL1",
                            CategoryOfInvolvement = "Significant ownership (Operations)",
                            RelatedCategorySymbol = "PL1",
                            Description = "The company owns 10-50 percent of another company with involvement in predatory lending activities.",
                            OwnershipYesNo = true,
                            RevenueRangeYesNo = false,
                            RevenueRange = new Dictionary<int,PIRange>()
                            {
                                { 0, new PIRange(){ RangeId = 1, NA = true, Start = -1, Stop = -1}},
                                { 1, new PIRange(){ RangeId = 2, NA = true, Start = -1, Stop = -1}},
                                { 2, new PIRange(){ RangeId = 3, NA = true, Start = -1, Stop = -1}},
                                { 3, new PIRange(){ RangeId = 4, NA = true, Start = -1, Stop = -1}},
                                { 4, new PIRange(){RangeId = 5, NA = true, Start = -1, Stop = -1}}
                            }
                    }
                }
            });
        }

        #endregion

        [TestCleanup]
        public void Cleanup()
        {
            var mongoClient = new MongoClient(dbCnx);
            mongoClient.DropDatabase(databaseName);
        }

        [TestMethod]
        [Owner("Mihai Stanescu")]
        public void GetIndicatorsCategoryBySymbol_PIIndicatorRepositoryTests()
        {
            var palmOilCategories = piIndicatorRepository.GetIndicatorCategories("PM");

            Assert.IsNotNull(piIndicators.Where(po => po.Symbol == "PM").SingleOrDefault(), "The PI indicator cannot be null.");
            var inMemoryPIIndicatorCategories = piIndicators.Where(po => po.Symbol == "PM").Single().Categories;
            Assert.AreEqual(inMemoryPIIndicatorCategories.Count, palmOilCategories.Count, "The number of categories for the PI indicator is different than the expected one.");
            Assert.AreEqual(inMemoryPIIndicatorCategories.Count(po => po.OwnershipYesNo), palmOilCategories.Count(po => po.OwnershipYesNo), "The number of significant ownership PI is different than the expected one.");
            Assert.AreEqual(inMemoryPIIndicatorCategories.Count(po => po.RevenueRangeYesNo), palmOilCategories.Count(po => po.RevenueRangeYesNo), "The number of revenue range PI is different than the expected one.");
            Assert.IsFalse(palmOilCategories.Any(po => po.OwnershipYesNo && !po.RevenueRangeYesNo && po.RevenueRange.Any(rr => !rr.Value.NA)), "A category cannot be significant ownership and have revenue range defined.");
            Assert.IsFalse(palmOilCategories.Any(po => po.OwnershipYesNo && po.RevenueRangeYesNo), "A category cannot be significant ownership and revenue range.");
            Assert.IsFalse(palmOilCategories.Any(po => po.RevenueRangeYesNo && po.RevenueRange.All(rr => rr.Value.NA)), "A category cannot be revenue range and not have any ranges defined.");
            Assert.IsFalse(palmOilCategories.Any(po => po.RevenueRange.Count != 5), "The number of revenue ranges must be equal to 5");
        }
    }
}
